/**************************************************************************//**
 *
 *  \copyright  This software is the property of  Technologies. Any
 *              information contained in this doc should not be reproduced,
 *              or used, or disclosed without the written authorization from
 *               Technologies.
 *
 *  \brief      This is a source file to make seed and verify a key.
 *
 *  \file       bl_access_udsdemo.c
 *  \ingroup    security_manager_module
 *  \author     
 *
 *  \version    5.1.0
 *  \date       27/03/2018
 *
 *  \par        Changelist
 *      Version  | Date       | Authors          | CR# | Descriptions
 *      -------- | ---------- | ---------------- | --- | ------------
 *      01.00.00 | 25/03/2018 | xucong      | N/A | Boot010001
 *
 *****************************************************************************/
#include "bl_common.h"
#include "bl_timer.h"
#include "bl_security_funcfg.h"
#include "bl_access_udsdemo.h"
#include "bl_adpt_uds_platform.h"
#include "bl_dcm_cfg.h"
#include "bl_crc32_bzip2.h"
/*****************************************************************************
 *  QAC Suppression
 *****************************************************************************/
/*PRQA S 602,1532,3212,3227,3453 EOF*/
/*
 * MISRA-C:2004 20.2(602):The identifier is reserved for use by the library.
 * The Bootloader do not use any library funtion and use the underscores to
 * indicate that the function is a interal function.
 *
 * 1532:The function is only referenced in one translation unit.
 * all functions in this file are configurations in the Security Module.
 *
 * 3212:This explicit cast is redundant and could be removed.
 * ACC_UDSDEMO_KEY_FROM_BUF and ACC_UDSDEMO_SEED_TO_BUF are not explicit cast.
 *
 * 3227:The parameter is never modified and so it could be declared with const.
 * Acc_UdsDemoGetSeed, the seed will be modify.
 * Acc_UdsDemoVerifyKey, the key is declared with const.
 *
 * MISRA-C:2004 19.7(3453):A function could probably be used instead of this
 * function-like macro.
 * ACC_UDSDEMO_KEY_FROM_BUF macro do not have side-effect.
 * ACC_UDSDEMO_SEED_TO_BUF macro do not have side-effect.
 *
 */

/*****************************************************************************
 *  Verify The Configurations of Macro
 *****************************************************************************/
#if ((SECM_ACCESS_KEY_SIZE != 4u) && (SECM_ACCESS_KEY_SIZE != 2u))
#error "The size of a key is only four or two, other values are invalid."
#endif

#if ((SECM_ACCESS_SEED_SIZE != 4u) && (SECM_ACCESS_SEED_SIZE != 2u))
#error "The size of a seed is only four or two, other values are invalid."
#endif
/*****************************************************************************
 *  Internal Macro Definitions
 *****************************************************************************/
#if (SECM_ACCESS_KEY_SIZE == 4u)    //進入該選項
#define ACC_UDSDEMO_KEY_MASK                (0xA5CEFDB6UL)
#define ACC_UDSDEMO_KEY_FROM_BUF(buf)       BL_BE32_TO_MCU(buf)   //buf = * buf
#elif (SECM_ACCESS_KEY_SIZE == 2u)
#define ACC_UDSDEMO_KEY_MASK                (0xDFB6u)
#define ACC_UDSDEMO_KEY_FROM_BUF(buf)       BL_BE16_TO_MCU(buf)
#endif

#if (SECM_ACCESS_SEED_SIZE == 4u)  //進入該選項
/** \brief It is used to calculate the random seed*/
#define ACC_UDSDEMO_RANDOM_SEED             (16807UL)
#define ACC_UDSDEMO_SEED_INITVALUE          (0x12350012UL)
#define ACC_UDSDEMO_SEED_TO_BUF(seed,buf)   BL_MCU_TO_BE32(buf,seed)  //*buf = seed
#elif (SECM_ACCESS_SEED_SIZE == 2u)
/** \brief It is used to calculate the random seed*/
#define ACC_UDSDEMO_RANDOM_SEED             (16807u)
#define ACC_UDSDEMO_SEED_INITVALUE          (0x1235u)
#define ACC_UDSDEMO_SEED_TO_BUF(seed,buf)   BL_MCU_TO_BE16(buf,seed)
#endif

/*****************************************************************************
 *  Internal Type Definitions
 *****************************************************************************/
#if (SECM_ACCESS_SEED_SIZE == 4u)   //是該選項
typedef bl_u32_t bl_UdsDemoSeed_t;
#elif (SECM_ACCESS_SEED_SIZE == 2u)
typedef bl_u16_t bl_UdsDemoSeed_t;
#endif

#if (SECM_ACCESS_KEY_SIZE == 4u)   //是該選項
typedef bl_u32_t bl_UdsDemoKey_t;
#elif (SECM_ACCESS_KEY_SIZE == 2u)
typedef bl_u16_t bl_UdsDemoKey_t;
#endif

/*****************************************************************************
 *  Internal Structure Definitions
 *****************************************************************************/

/*****************************************************************************
 *  Internal Function Declarations
 *****************************************************************************/
/** \brief Calculate the key from the gs_UdsDemoSeed.*/
static bl_UdsDemoKey_t _Acc_UdsDemoCalculateKey(void);

/*****************************************************************************
 *  Internal Variable Definitions
 *****************************************************************************/
STATIC bl_UdsDemoSeed_t gs_UdsDemoSeed;  //u32

static bl_u8_t AccessLevel;
static bl_u32_t kArray[4];
static bl_u8_t SerialNumberLast4[4];
static bl_u32_t seedArray[2];

/*****************************************************************************
 *  Global Variable Definitions
 *****************************************************************************/

/*****************************************************************************
 *  Function Definitions
 *****************************************************************************/
/**************************************************************************//**
 *
 *  \details Initialize the DEMO security access used for UDS.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoInit(void)
{
    gs_UdsDemoSeed = ACC_UDSDEMO_SEED_INITVALUE;

    return ;
}

/**************************************************************************//**
 *
 *  \details Make a new seed.
 *
 *  \since  V5.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoMakeNewSeed(void)
{
    bl_u32_t currenttick;
    currenttick = Tim_seedtick_Get();
    currenttick = currenttick %1000;
    gs_UdsDemoSeed = gs_UdsDemoSeed * ACC_UDSDEMO_RANDOM_SEED * currenttick;

    return ;
}

/**************************************************************************//**
 *
 *  \details Get current seed value.
 *
 *  \param[out]  seed - the value of current seed.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
void Acc_UdsDemoGetSeed(bl_Buffer_t *seed)
{
    ACC_UDSDEMO_SEED_TO_BUF(gs_UdsDemoSeed,seed);  // seed = gs_UdsDemoSeed  

    return ;
}

/**************************************************************************//**
 *
 *  \details Set the access level.
 *
 *  \param[in] level - the value of access level.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
void Secm_SetAccessLevel(bl_u8_t level)
{   
    AccessLevel = level;
    uint8_t * u8pserial;
    u8pserial = (uint8_t *)(K_KEY_ADDRESS + F18C_LENGTH-4);
    SerialNumberLast4[0]=*(u8pserial+0);
    SerialNumberLast4[1]=*(u8pserial+1);
    SerialNumberLast4[2]=*(u8pserial+2);
    SerialNumberLast4[3]=*(u8pserial+3);
    if(AccessLevel == 0)//Level1
    {
        kArray[0] = SerialNumberLast4[0];
        kArray[1] = SerialNumberLast4[1];
        kArray[2] = SerialNumberLast4[2];
        kArray[3] = SerialNumberLast4[3];
    }
    else if(AccessLevel == 1)//Level2
    {
        //kArray[n] = SerialNumberLast4[n] ROR 3
        kArray[0] = (bl_u8_t)(SerialNumberLast4[0] >> 3) | (bl_u8_t)(SerialNumberLast4[0] << 5);
        kArray[1] = (bl_u8_t)(SerialNumberLast4[1] >> 3) | (bl_u8_t)(SerialNumberLast4[1] << 5);
        kArray[2] = (bl_u8_t)(SerialNumberLast4[2] >> 3) | (bl_u8_t)(SerialNumberLast4[2] << 5);
        kArray[3] = (bl_u8_t)(SerialNumberLast4[3] >> 3) | (bl_u8_t)(SerialNumberLast4[3] << 5);
    }
    return ;
}

/**************************************************************************//**
 *
 *  \details Verify the value of transmitted key whether is right.
 *
 *  \param[in]  key - the value of transmitted key.
 *
 *  \return If the transmitted key value is right return BL_ERR_OK, otherwise
 *          return BL_ERR_NOT_OK.
 *
 *  \retval BL_ERR_OK - the transmitted key value is right.
 *  \retval BL_ERR_NOT_OK - the transmitted key value is NOT right.
 *
 *  \since  V1.0.0
 *
 *****************************************************************************/
bl_Return_t Acc_UdsDemoVerifyKey(const bl_Buffer_t *key)
{
    bl_Return_t ret = BL_ERR_NOT_OK;
    bl_UdsDemoKey_t calKey;
    bl_UdsDemoKey_t tranKey;

    calKey = _Acc_UdsDemoCalculateKey();   //這是相當於本地算出來的
    tranKey = ACC_UDSDEMO_KEY_FROM_BUF(key);  // tranKey = *key  --這是相當於 診斷上收回來的數據；

    if (calKey == tranKey)
    {
        ret = BL_ERR_OK;
    }

    return ret;
}

bl_UdsDemoKey_t u32seedtokey = 0;

bl_u32_t encipher(unsigned int num_rounds, bl_u32_t v[2], bl_u32_t const k[4]) 
{ 
    unsigned int i; 
    bl_u32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9; 
    for (i=0; i < num_rounds; i++) 
    { 
    v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); 
    sum += delta; 
    v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]);
    } 
    v[0]=v0; v[1]=v1; 
    return v0;
}

/**************************************************************************//**
 *
 *  \details An algorithm is used to calculate the key by a seed.
 *
 *  \return the key value
 *
 *  \since V1.0.0
 *
 *****************************************************************************/
 bl_UdsDemoKey_t _Acc_UdsDemoCalculateKey(void)
{
    bl_u32_t    SaccKey;
    bl_u8_t     MagicSeed[4] = {0};
    Acc_UdsDemoGetSeed(MagicSeed);
    //MagicSeed[0] as the MSB of seedArray[0],4 bytes combined to 1 u32_t
    seedArray[0] = MagicSeed[0]<<24;
    seedArray[0] |= MagicSeed[1]<<16;
    seedArray[0] |= MagicSeed[2]<<8;
    seedArray[0] |= MagicSeed[3];
    //seedArray[1] is the complement of seedArray[0]
    seedArray[1] = ~seedArray[0];

    SaccKey = encipher(2, seedArray, kArray);
    return SaccKey;
}
